Skip to content

Conversation

@zxPhoenix
Copy link
Contributor

@zxPhoenix zxPhoenix commented Oct 22, 2025

🔧 Type of changes

  • new bid adapter
  • bid adapter update
  • new feature
  • new analytics adapter
  • new module
  • module update
  • bugfix
  • documentation
  • configuration
  • dependency update
  • tech debt (test coverage, refactorings, etc.)

✨ What's the context?

Make Unruly's PBS adapter sending the GPID to the Unruly endpoint. [Issue #4252]

🧠 Rationale behind the change

Why did you choose to make these changes? Were there any trade-offs you had to consider?

🔎 New Bid Adapter Checklist

  • verify email contact works
  • NO fully dynamic hostnames
  • geographic host parameters are NOT required
  • direct use of HTTP is prohibited - implement an existing Bidder interface that will do all the job
  • if the ORTB is just forwarded to the endpoint, use the generic adapter - define the new adapter as the alias of the generic adapter
  • cover an adapter configuration with an integration test

🧪 Test plan

Unit tests are updated
Manual testing is done

🏎 Quality check

  • Are your changes following our code style guidelines?
  • Are there any breaking changes in your code?
  • Does your test coverage exceed 90%?
  • Are there any erroneous console logs, debuggers or leftover code in your changes?

@AntoxaAntoxic AntoxaAntoxic linked an issue Oct 24, 2025 that may be closed by this pull request
Comment on lines 37 to 75
private static final TypeReference<UnrulyExtImp<?, ExtImpUnruly>> UNRULY_EXT_TYPE_REFERENCE =
new TypeReference<>() {
};

private final String endpointUrl;
private final JacksonMapper mapper;

public UnrulyBidder(String endpointUrl, JacksonMapper mapper) {
this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl));
this.mapper = Objects.requireNonNull(mapper);
}

@Override
public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request) {
final List<HttpRequest<BidRequest>> httpRequests = request.getImp().stream()
.map(this::modifyImp)
.map(imp -> createSingleRequest(imp, request))
.toList();

return Result.withValues(httpRequests);
}

private Imp modifyImp(Imp imp) {

final UnrulyExtImp<?, ExtImpUnruly> unrulyExtImp = parseImpExt(imp);
return imp.toBuilder()
.ext(mapper.mapper().valueToTree(ExtPrebid.of(null, parseImpExt(imp))))
.ext(mapper.mapper().valueToTree(UnrulyExtImp.of(
null,
unrulyExtImp.getBidder(),
unrulyExtImp.getGpid())))
.build();
}

private ExtImpUnruly parseImpExt(Imp imp) {
private UnrulyExtImp<?, ExtImpUnruly> parseImpExt(Imp imp) {
try {
return mapper.mapper().convertValue(imp.getExt(), UNRULY_EXT_TYPE_REFERENCE).getBidder();
return mapper.mapper().convertValue(imp.getExt(), UNRULY_EXT_TYPE_REFERENCE);
} catch (IllegalArgumentException e) {
throw new PreBidException(e.getMessage());
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why the bidder has to parse the imp.ext while it should be passing through as-is, so I suggest the following approach

    @Override
    public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request) {
        final List<HttpRequest<BidRequest>> httpRequests = request.getImp().stream()
                .map(this::modifyImp)
                .map(imp -> createSingleRequest(imp, request))
                .toList();

        return Result.withValues(httpRequests);
    }

    private Imp modifyImp(Imp imp) {
        final ObjectNode impExt = imp.getExt();
        final ObjectNode modifiedImpExt = mapper.mapper().createObjectNode();
        modifiedImpExt.set("bidder", impExt.get("bidder"));
        modifiedImpExt.set("gpid", impExt.get("gpid"));
        return imp.toBuilder().ext(modifiedImpExt).build();
    }

    private HttpRequest<BidRequest> createSingleRequest(Imp imp, BidRequest request) {
        final BidRequest outgoingRequest = request.toBuilder().imp(Collections.singletonList(imp)).build();
        return BidderUtil.defaultRequest(outgoingRequest, endpointUrl, mapper);
    }

Also don't forget to clean up unused constants and classes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @AntoxaAntoxic ,

I’m not the owner of the Unruly adapter, so I’d like to add GPID with the minimum possible changes to the original code — avoiding any unexpected architectural or other modifications that could affect the Unruly team.

As I understand it, the existing code parses the impExt into a custom class to extract only the required fields from the bidder object — in this case, just siteId. All other fields are ignored.

I’ve noticed the same approach being used for many other bidders (e.g., ix, rubicon, pubmatic, openx, grid, etc.), so it appears to be a common pattern.

However, your suggestion would copy all fields from the bidder object, including those that Unruly doesn’t expect to receive.

Would you prefer that I apply your proposal, keep the current approach, or you could contact the Unruly team to discuss a possible refactor since that would be outside the scope of simply adding the GPID field?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, looks like they need only the siteId and gpid fields. Okay we can go with your approach, but I suggest to simplify the DTO you've created

@Value(staticConstructor = "of")
public class UnrulyExtImp {

    ExtImpUnruly bidder;

    String gpid;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@zxPhoenix zxPhoenix force-pushed the unruly-support-gpid branch from 680e2c2 to 14248bc Compare October 28, 2025 18:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unruly - support gpid

2 participants